package common

import (
	"fmt"
	"os"
	"path/filepath"

	"go.uber.org/zap"
	"go.uber.org/zap/zapcore"
	"gopkg.in/natefinch/lumberjack.v2"
)

// MyType 是我们想要提供的类型
type ZapLogger struct {
	logger *zap.SugaredLogger
}

// NewMyType 是一个构造函数，用于创建 MyType 的新实例
func NewZapLogger(filePath string, FilePerms int) *ZapLogger {
	log, _ := ZapLoggerInit(filePath, FilePerms)
	return &ZapLogger{logger: log}
}

func (zl *ZapLogger) Debug(args ...interface{}) {
	zl.logger.Debug(args)
}

func (zl *ZapLogger) Debugf(template string, args ...interface{}) {
	zl.logger.Debugf(template, args...)
}

func (zl *ZapLogger) Info(args ...interface{}) {
	zl.logger.Info(args...)
}

func (zl *ZapLogger) Infof(template string, args ...interface{}) {
	zl.logger.Infof(template, args...)
}

func (zl *ZapLogger) Warn(args ...interface{}) {
	zl.logger.Warn(args...)
}

func (zl *ZapLogger) Warnf(template string, args ...interface{}) {
	zl.logger.Warnf(template, args...)
}

func (zl *ZapLogger) Error(args ...interface{}) {
	zl.logger.Error(args...)
}

func (zl *ZapLogger) Errorf(template string, args ...interface{}) {
	zl.logger.Errorf(template, args...)
}

func (zl *ZapLogger) DPanic(args ...interface{}) {
	zl.logger.DPanic(args...)
}

func (zl *ZapLogger) DPanicf(template string, args ...interface{}) {
	zl.logger.DPanicf(template, args...)
}

func (zl *ZapLogger) Panic(args ...interface{}) {
	zl.logger.Panic(args...)
}

func (zl *ZapLogger) Panicf(template string, args ...interface{}) {
	zl.logger.Panicf(template, args...)
}

func (zl *ZapLogger) Fatal(args ...interface{}) {
	zl.logger.Fatal(args...)
}

func (zl *ZapLogger) Fatalf(template string, args ...interface{}) {
	zl.logger.Fatalf(template, args...)
}

// 这个供外部调用
func ZapLoggerInit(filePath string, FilePerms int) (*zap.SugaredLogger, error) {
	fileName, fileErr := createFileWithPerms(filePath, os.FileMode(FilePerms))
	if fileErr != nil {
		// 使用 %v 来打印 error 类型的变量
		fmt.Printf("Error: %v\n", fileErr)
		return nil, fileErr
	}
	fmt.Printf("日志文件路径: %s\n", fileName)
	syncWriter := zapcore.AddSync(
		&lumberjack.Logger{
			Filename: fileName, //文件名称
			MaxSize:  521,      // MB
			// MaxAge:     0,
			MaxBackups: 0, //最大备份
			LocalTime:  true,
			Compress:   true, //是否启用压缩
		})
	// 编码
	encoder := zap.NewProductionEncoderConfig()
	// 时间格式
	encoder.EncodeTime = zapcore.ISO8601TimeEncoder
	core := zapcore.NewCore(
		// 编码器
		zapcore.NewJSONEncoder(encoder),
		syncWriter,
		zap.NewAtomicLevelAt(zap.DebugLevel))
	log := zap.New(
		core,
		zap.AddCaller(),
		zap.AddCallerSkip(1))
	return log.Sugar(), nil
}

// 创建一个多层目录下的文件，并设置权限, 如果文件已存在，则返回文件的路径；如果不存在，则创建并返回文件路径
func createFileWithPerms(filePath string, perms os.FileMode) (string, error) {
	// 检查文件或目录是否存在
	fileInfo, err := os.Lstat(filePath)
	if err == nil {
		// 文件或目录已存在
		if fileInfo.IsDir() {
			// 如果已存在的是目录，返回错误
			return "", fmt.Errorf("无法创建文件 '%s'，因为该路径已存在且是一个目录", filePath)
		}
		// 如果已存在的是文件，则返回文件路径
		return filePath, nil
	}
	if !os.IsNotExist(err) {
		// 如果发生其他错误（如权限问题），则返回错误
		return "", fmt.Errorf("检查文件 '%s' 时发生错误: %v", filePath, err)
	}

	// 创建多级目录
	err = os.MkdirAll(filepath.Dir(filePath), os.ModePerm) // 使用 os.ModePerm 允许所有权限，但文件权限会由下面的 os.Create 设置
	if err != nil {
		return "", fmt.Errorf("无法创建目录 '%s': %v", filepath.Dir(filePath), err)
	}

	// 创建文件
	file, err := os.Create(filePath)
	if err != nil {
		return "", fmt.Errorf("无法创建文件 '%s': %v", filePath, err)
	}
	// 关闭文件，因为我们只需要路径
	defer file.Close()

	// 设置文件权限
	err = file.Chmod(perms)
	if err != nil {
		return "", fmt.Errorf("无法设置文件 '%s' 的权限: %v", filePath, err)
	}

	// 返回新创建文件的路径
	return filePath, nil
}
